#############购物车######################
'''
１．
    京东的网址　登录用户可以实现购物车，未登录用户也可以实现购物车
    淘宝的网址，必须是登陆用户才可以实现购物车

２．问题
    登录用户数据保存在哪里？　　服务器里　redis
    未登录用户数据保存在哪里？　客户端　cookie

3.保存那些数据？
    redis:
        user_id, sku_id(商品id), count(数量), selected(选中状态)

    cookie:
        sku_id, count, selected

4.数据的组织
    redis:

        user_id:
            sku_id:count
        selected

    例：
    user_1   id:数量
              1:10
              2:20
              3:30
    记录选中商品：
        １,３


    cookie:
        {
            sku_id:{count:xxx, selected:xxxx},
            sku_id:{count:xxx, selected:xxxx},
            sku_id:{count:xxx, selected:xxxx},
        }

5.cookie字典转换为字符串保存起来，数据没有加密



添加购物车

    前端：　我们点击添加购物车之后，前端将商品id发送给后端

    后端：
        请求：接收参数，验证参数
        业务逻辑：　根据商品id查询数据库看看商品id是否正确
            　　　 数据入库

                　　  登录用户入redis
                         连接redis
                         获取用户id
                         hash
                         set
                         返回响应

                      未登录用户用cookie
                    　    先有cookie字典
                        　字典转换为bytes
                          bytes类型数据转换为base64
                          设置cookie
                          返回响应

        路由：　POST carts/
        步骤：　
            １．接收数据
            ２，验证数据
            ３．判断用户的登录状态
            ４．登录用户保存redis
                4.1连接redis
                4.2操作hash
                4.3操作set
                4.4返回响应
            ５．未登录用户保存cookie
                5.1先有cookie字典
                5.2字典数据转换为bytes
                5.3bytes类型数据转换为base64编码
                5.4设置cookie
                5.5返回响应


查询购物车（个人中心展示，省市区）

１．判断用户是否登录
２．登录用户查询redis
    ２．１连接redis
    ２．２ hash  {sku_id:count}
    ２．３ set  {sku_id}
    ２．４　遍历判断
    ２．５　根据商品id查询商品信息
    ２．６　将对象数据转换为字典数据
    ２．７　返回响应

３．未登录用户查询cookie
    ３．１　读取cookie数据
    ３．２判断是否存在购物车数据
        如果存在则解码　{sku_id:{count:xxx,selected:xxxx}}
        如果不存在初始化字典
    ３．３　根据商品id查询商品信息
    ３．４　将对象数据转换为字典数据
    ３．５　返回响应


修改购物车
    １．获取用户信息
    ２．接收数据
    ３．验证数据
    ４．判断用户是否登录
    ４．０登录用户更新redis
        ４．１连接redis
        ４．２hash
        ４．３set
        ４．４返回响应
    ５．０未登录用户更新redis
    ５．１先读取购物车数据
    ５．２更新数据
    ５．３更新完后，字典进行编码和base64加密
    ５．４返回响应

删除购物车
    １．接收请求
    ２．验证参数
    ３．判断用户是否登录
        ４．登录用户操作
            ４．１连接redis
            ４．２hash
            ４．３set
            ４．４返回响应
        ５．未登录用户操作cookie
            ５．１读取cookie中的购物车数据
            判断数据是否存在
            存在则解码
            不存在则初始化字典
            ５．２删除数据{}
            ５．３我们需要对字典数据进行编码和base64处理
            ５．４设置cookie
            ５．５返回响应

'''
import json

from django import http
from django.views import View
from django_redis import get_redis_connection
import pickle
import base64
from apps.goods.models import SKU




class CartsView(View):

    def post(self,request):

    #     １．接收数据
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')

    #     ２，验证数据
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code':400, 'errmsg':'没有此商品'})

        #类型强制转换
        try:
            count = int(count)
        except Exception:
            count = 1

    #     ３．判断用户的登录状态
        user = request.user
        if user.is_authenticated:
              #４．登录用户保存redis

              #     4.1连接redis
            redis_cli = get_redis_connection('carts')

              #     4.2操作hash
            redis_cli.hset('carts_%s'%user.id,sku_id,count)

              #     4.3操作set
            redis_cli.sadd('selected_%s'%user.id,sku_id)

             #     4.4返回响应
            return JsonResponse({'code':0, 'errmsg':'ok'})

        else:
        # ５．未登录用户保存cookie
        #     5.0　先读取cookie数据
            cookie_carts = request.COOKIES.get('carts')

            if cookie_carts:
                carts = pickle.loads(base64.b64decode(cookie_carts))

            else:
                # 5.1先有cookie字典
                carts = {}

                # 判断新增的商品，有没有在购物车里
            if sku_id in carts:
                # 在购物车中有商品id
                # 数量累加
                origin_count = carts[sku_id]['count']
                count+=origin_count
            carts[sku_id] = {
                'count': count,
                'selected': True
            }


        # 5.2字典数据转换为bytes

            carts_bytes = pickle.dumps(carts)

        # 5.3bytes类型数据转换为base64编码

            base64b64encode = base64.b64encode(carts_bytes)

        # 5.4设置cookie
            request = JsonResponse({'code':0, 'errmsg':'ok'})
            request.set_cookie('carts',base64b64encode.decode(),max_age=3600*24*12)

        # 5.5返回响应
            return request


    def get(self,request):

        # １．判断用户是否登录
        user = request.user
        if user.is_authenticated:
        #  ２．登录用户查询redis
            #  ２．１连接redis
            redis_cli = get_redis_connection('carts')

            #  ２．２ hash　{sku_id: count}
            sku_id_count = redis_cli.hgetall('carts_%s'%user.id)

            #  ２．３ set　 {sku_id}
            selected_ids = redis_cli.smembers('selected_%s'%user.id)

            #  将redis的数据转换和cookie一样，这样就可以在后续操作的时候统一操作
            carts = {}
            for sku_id,count in sku_id_count.items():
                carts[int(sku_id)] = {
                    'count':int(count),
                    'selected':sku_id in selected_ids
                }
        else:
        #  ３．未登录用户查询cookie
            #  ３．１　读取cookie数据
            cookie_carts = request.COOKIES.get('carts')

            #  ３．２判断是否存在购物车数据
            if cookie_carts is not None:

                #  如果存在则解码　{sku_id: {count: xxx, selected: xxxx}}
                carts = pickle.loads(base64.b64decode(cookie_carts))

            else:
                #  如果不存在初始化字典
                carts = {}

        #  ３．３　根据商品id查询商品信息
        # 可以直接遍历carts,也可以直接获取字典的所有的key
        sku_ids = carts.keys()
        # 也可以遍历，也可以用in
        skus = SKU.objects.filter(id__in=sku_ids)
        sku_list = []
        for sku in skus:
        #  ３．４　将对象数据转换为字典数据
            sku_list.append({
                'id':sku.id,
                'price':str(sku.price),
                'name':sku.name,
                'default_image_url':sku.default_image.url,
                'selected': str(carts.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'count': carts.get(sku.id).get('count'),
                'amount':str(sku.price * carts.get(sku.id).get('count')),
            })
        return JsonResponse({'code':0,'errmsg':'ok','cart_skus':sku_list})


    def put(self,request):
    #     １．获取用户信息
        user = request.user

    #     ２．接收数据
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected')

    #     ３．验证数据
        if not all([sku_id,count]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})

        try:
            SKU.objects.get(id=sku_id)

        except SKU.DoesNotExist:
            return ({'code': 400, 'errmsg': '没有此商品'})

        try:
            count = int(count)

        except Exception:
            count = 1

    #     ４．判断用户是否登录
        if user.is_authenticated:
    #     ４．０登录用户更新redis
    #     ４．１连接redis
            redis_cli = get_redis_connection('carts')

    #     ４．２hash
            redis_cli.hset('carts_%s'%user.id,sku_id,count)

    #     ４．３set
            if selected:
                redis_cli.sadd('selected_%s'%user.id,sku_id)
            else:
                redis_cli.srem('selected_%s'%user.id,sku_id)

    #     ４．４返回响应
            return JsonResponse({'code':0,'errmsg':'ok','cart_sku':{'count':count,'selected':selected}})

        else:
        # ５．０未登录用户更新cookie
        # ５．１先读取购物车数据
            cookie_cart = request.COOKIE.get('carts')
            #判断有没有
            if cookie_cart  :
                # 如果有则解密数据
                carts = pickle.loads(base64.b64decode(cookie_cart))
            else:
                carts = {}

        # ５．２更新数据
            if sku_id in carts:
                carts[sku_id] = {
                    'count':count,
                    'selected':selected
                }

        # ５．３更新完后，字典进行编码和base64加密
            new_carts = base64.b64encode(pickle.dumps(carts))
            response = JsonResponse({'code':0,'errmsg':'ok','cart_sku':{'count':count,'selected':selected}})
            response.set_cookie('carts',new_carts.decode(),max_age=14*24*3600)

        # ５．４返回响应
            return response


    def delete(self,request):
        # １．接收请求
        data = json.loads(request.body.decode())

        # ２．验证参数
        sku_id = data.get('sku_id')
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code':400,'errmsg':'没有此商品'})

        # ３．判断用户是否登录
        user = request.user
        if user.is_authenticated:
        # ４．登录用户操作
            # ４．１连接redis
            redis_cli = get_redis_connection('carts')

            # ４．２hash
            redis_cli.hdel('carts_%s'%user.id,sku_id)

            # ４．３set
            redis_cli.srem('selected_%s'%user.id,sku_id)

            # ４．４返回响应
            return JsonResponse({'code':0,'errmsg':'ok'})

        else:
        # ５．未登录用户操作cookie
            # ５．１读取cookie中的购物车数据
            cookie_cart = request.COOKIES.get('cart')

            # 判断数据是否存在
            if cookie_cart is not None:
            # 存在则解码
                carts = pickle.loads(base64.b64decode(cookie_cart))
            else:
            # 不存在则初始化字典
                carts = {}

            # ５．２删除数据 {}
            del carts[sku_id]

            # ５．３我们需要对字典数据进行编码和base64处理
            new_carts = base64.b64encode(pickle.dumps(cookie_cart))

            # ５．４设置cookie
            response = JsonResponse({'code':0,'errmsg':'ok'})
            response.set_cookie('carts',new_carts.decode(),max_age=14*24*3600)

            # ５．５返回响应
        return response




from django.http import JsonResponse
class CartsSelectedAllView(View):


    def put(self,request):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected', True)

        # 校验参数
        if selected:
            if not isinstance(selected, bool):
                return JsonResponse({'code':400,'errmsg':'参数selected有误'})

        # 判断用户是否登录
        user = request.user
        if  user.is_authenticated:
            # 用户已登录，操作redis购物车
            redis_conn = get_redis_connection('carts')
            cart = redis_conn.hgetall('carts_%s' % user.id)
            sku_id_list = cart.keys()
            if selected:
                # 全选
                redis_conn.sadd('selected_%s' % user.id, *sku_id_list)
            else:
                # 取消全选
                redis_conn.srem('selected_%s' % user.id, *sku_id_list)
            return JsonResponse({'code': 0, 'errmsg': '全选购物车成功'})

        else:
            # 用户未登录，操作cookie购物车
            cart = request.COOKIES.get('carts')
            response = JsonResponse({'code': 0, 'errmsg': '全选购物车成功'})
            if cart is not None:
                cart = pickle.loads(base64.b64decode(cart.encode()))
                for sku_id in cart:
                    cart[sku_id]['selected'] = selected
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('carts', cookie_cart, max_age=7 * 24 * 3600)

            return response







class CartsSimpleView(View):
    """商品页面右上角购物车"""

    def get(self, request):
        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 用户已登录，查询Redis购物车
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            # 将redis中的两个数据统一格式，跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookie购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

    # 构造简单购物车JSON数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image.url
            })

            # 响应json列表数据
        return http.JsonResponse({'code': 0, 'errmsg': 'OK', 'cart_skus': cart_skus})

